home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / telnet.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  13KB  |  563 lines

  1. /* Internet Telnet client
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  
  5. /****************************************************************************
  6. *    $Id: telnet.c 1.2 93/07/16 11:51:27 ROOT_DOS Exp $
  7. *    08 May 93    1.2        GT    Fix warnings.                                    *
  8. *
  9. *  ATARI Version by David Nash - dnash@chaos.demon.co.uk
  10. *
  11. *    10.03.93 - Lookup port number from service nmemonic added
  12. *
  13. *  __stdargs dotelnet, tel_output
  14. ****************************************************************************/
  15.  
  16. #include <stdio.h>
  17. #ifdef    __TURBOC__
  18. #include <io.h>
  19. #include <fcntl.h>
  20. #endif
  21. #ifdef ATARI
  22. #include <ctype.h>
  23. #endif
  24. #include "global.h"
  25. #include "mbuf.h"
  26. #include "socket.h"
  27. #include "telnet.h"
  28. #include "session.h"
  29. #include "proc.h"
  30. #include "tty.h"
  31. #include "commands.h"
  32. #include "netuser.h"
  33.  
  34. static int filemode __ARGS((FILE *fp,int mode));
  35.          int service_code(char *);
  36. #define    CTLZ    26
  37.  
  38. int Refuse_echo = 0;
  39. int Tn_cr_mode = 0;    /* if true turn <cr> to <cr-nul> */
  40.  
  41. /*
  42.     Define port numbers for common services
  43. */
  44. static struct svc {
  45.     char *name;
  46.     int service_code;
  47.     } services[] = {
  48.         "tcpmux",        1,                            /* TCP Multiplexor                    */
  49.           "rje",            5,                            /* Remote Job Entry                    */
  50.           "echo",            7,                            /* Echo                                    */
  51.           "discard",        9,                            /* Discard                                */
  52.           "users",            11,                        /* Active Users                        */
  53.           "systat",      11,                        /* Active Users                        */
  54.           "daytime",        13,                        /* Daytime                                */
  55.           "netstat",        15,                        /* Who is up or NETSTAT                */
  56.           "qotd",        17,                        /* Quote of the Day                    */
  57.           "quote",            17,                        /* Quote of the Day                    */
  58.           "chargen",        19,                        /* Character Generator                */
  59.           "ftp-data",        20,                        /* File Transter Protocol (Data)    */
  60.           "ftp",            21,                        /* File Transfer Protocol            */
  61.           "telnet",        23,                        /* Terminal Connection                */
  62.           "smtp",            25,                        /* Simple Mail Transfer Protocol */
  63.           "time",            37,                        /* Time                                    */
  64.           "rlp",            39,                        
  65.           "name",        42,                        /* Host Name Server                    */ 
  66.           "nameserver",    42,                        /* Host Name Server                    */
  67.           "whois",       43,                        /* Who Is                                */
  68.           "nicname",        43,                        /* Who Is                                */
  69.           "domain",        53,                         /* Domain Name Server                */
  70.           "bootps",        67,                        /* Bootstrap Protocol Server        */
  71.           "bootpc",        68,                        /* Bootstrap Protocol Client        */
  72.           "tftp",            69,                        /* Trivial File Transfer             */
  73.           "finger",        79,                        /* Finger                                */
  74.           "chat",        87,                        /* TTYlink                                */
  75.           "link",        87,                        /* TTYlink                                */
  76.           "ttylink",     87,                        /* TTYlink                                */
  77.           "dcp",            93,                        /* Device Control Protocol            */
  78.           "supdup",        95,                        /* SUPDUP Protocol                    */
  79.           "hostname",        101,                        /* NIC Host Name Server                */
  80.           "iso-tsap",    102,                        /* ISO-TSAP                                */
  81.           "x400",            103,                        /* X.400 Mail Service                */
  82.           "x400-snd",        104,                        /* X.400 Mail Sending                */
  83.           "sunrpc",      111,                        /* Sun Microsystems RPC                */
  84.           "auth",            113,                        /* Authentication Service            */
  85.           "uucp-path",    117,                        /* UUCP Path Service                    */
  86.           "nntp",            119,                        /* USENET News Transfer Protocol */
  87.           "ntp",            123,                        /* Network Time Protocol            */
  88.           "pwdgen",        129,                        /* Password Generator Protocol    */
  89.           "netbios-ssn",    139,                        /* NETBIOS Session Service            */
  90.           "snmp",            161,                        /* SNMP net monitor                    */
  91.           "snmp-trap",   162,                        /* SNMP traps                            */
  92.           "biff",            512,                        /* UNIX comsat                            */
  93.           "who",            513,                        /* UNIX rwho daemon                    */
  94.           "syslog",        514,                        /* system log                            */
  95.           "timed",            525,                        /* Time daemon                            */
  96.           (char *)0,        -1
  97.       };
  98.  
  99. #ifdef    DEBUG
  100. char *T_options[] = {
  101.     "Transmit Binary",
  102.     "Echo",
  103.     "",
  104.     "Suppress Go Ahead",
  105.     "",
  106.     "Status",
  107.     "Timing Mark"
  108. };
  109. #endif
  110.  
  111. /* Execute user telnet command */
  112.  
  113. int __stdargs dotelnet(argc,argv,p)
  114. int argc;
  115. char *argv[];
  116. void *p;
  117. {
  118.     struct session *sp;
  119.     struct sockaddr_in fsocket;
  120.  
  121.     /* Allocate a session descriptor */
  122.     if((sp = newsession(argv[1],TELNET)) == NULLSESSION){
  123.         tprintf("Too many sessions\n");
  124.         return 1;
  125.     }
  126.     fsocket.sin_family = AF_INET;
  127.     if(argc < 3)
  128.         fsocket.sin_port = IPPORT_TELNET;
  129.     else
  130.         fsocket.sin_port = service_code(argv[2]);        /* port # lookup - DFN */ 
  131.  
  132.     if (fsocket.sin_port < 0) {
  133.         tprintf("Unknown service: %s \n", argv[2]);
  134.         return -1;
  135.     }
  136.  
  137.     tprintf("Resolving %s... ",sp->name);
  138.     if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  139.         tprintf(Badhost,sp->name);
  140.         keywait(NULLCHAR,1);
  141.         freesession(sp);
  142.         return 1;
  143.     }
  144.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  145.         tprintf("Can't create socket\n");
  146.         keywait(NULLCHAR,1);
  147.         freesession(sp);
  148.         return 1;
  149.     }
  150.     return tel_connect(sp,(char *)&fsocket,SOCKSIZE);
  151. }
  152. /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
  153. int
  154. tel_connect(sp,fsocket,len)
  155. struct session *sp;
  156. char *fsocket;
  157. int len;
  158. {
  159.     unsigned int index;
  160.     struct telnet tn;
  161.  
  162.     index = (unsigned int) (sp - Sessions);
  163.     memset((char *)&tn,0,sizeof(tn));
  164.     tn.eolmode = Tn_cr_mode;
  165.     tn.session = sp;    /* Upward pointer */
  166.     sp->cb.telnet = &tn;    /* Downward pointer */
  167.     sockmode(sp->s,SOCK_ASCII);    /* Default to ascii mode */
  168.  
  169.     tprintf("Trying %s...\n",psocket((struct sockaddr *)fsocket));
  170.     if(connect(sp->s,fsocket,len) == -1){
  171.           tprintf("%s session %u failed: %s errno %d\n",
  172.          Sestypes[sp->type], index, sockerr(sp->s),errno);
  173.  
  174.         keywait(NULLCHAR,1);
  175.         freesession(sp);
  176.         return 1;
  177.     }
  178.     tprintf("%s session ",Sestypes[sp->type]);
  179.     tprintf("%u connected to %s\n",index,sp->name);
  180.     tnrecv(&tn);
  181.     return 0;
  182. }
  183.  
  184. /* Telnet input routine, common to both telnet and ttylink */
  185. void
  186. tnrecv(tn)
  187. struct telnet *tn;
  188. {
  189.     int c,s,index;
  190.     struct session *sp;
  191.     char *cp;
  192.  
  193.     sp = tn->session;
  194.     s = sp->s;
  195.  
  196.     index = (int) (sp - Sessions);
  197.  
  198.     /* Fork off the transmit process */
  199.     sp->proc1 = newproc("tel_out",1024,tel_output,0,tn,NULL,0);
  200.  
  201.     /* Process input on the connection */
  202.     while((c = recvchar(s)) != -1){
  203.         if(c != IAC){
  204.             /* Ordinary character */
  205.             if(!tn->remote[TN_TRANSMIT_BINARY])
  206.                 c &= 0x7f;
  207.  
  208.             tputc((char)c);
  209.             continue;
  210.         }
  211.         /* IAC received, get command sequence */
  212.         c = recvchar(s);
  213.         switch(c){
  214.         case WILL:
  215.             c = recvchar(s);
  216.             willopt(tn,c);
  217.             break;
  218.         case WONT:
  219.             c = recvchar(s);
  220.             wontopt(tn,c);
  221.             break;
  222.         case DO:
  223.             c = recvchar(s);
  224.             doopt(tn,c);
  225.             break;
  226.         case DONT:
  227.             c = recvchar(s);
  228.             dontopt(tn,c);
  229.             break;
  230.         case IAC:    /* Escaped IAC */
  231.             tputc((char)IAC);
  232.             break;
  233.         }
  234.     }
  235. quit:    /* A close was received from the remote host.
  236.      * Notify the user, kill the output task and wait for a response
  237.      * from the user before freeing the session.
  238.      */
  239.     sockmode(sp->output,SOCK_ASCII); /* Restore newline translation */
  240.     cp = sockerr(s);
  241.     tprintf("%s session %u", Sestypes[sp->type],index);
  242.     tprintf(" closed: %s\n", cp != NULLCHAR ? cp : "EOF");
  243.     killproc(sp->proc1);
  244.     sp->proc1 = NULLPROC;
  245.     close_s(sp->s);
  246.     sp->s = -1;
  247.     keywait(NULLCHAR,1);
  248.     freesession(sp);
  249. }
  250.  
  251. /* User telnet output task, started by user telnet command */
  252. void __stdargs tel_output(unused,tn1,p)
  253. int unused;
  254. void *tn1;
  255. void *p;
  256. {
  257.     struct session *sp;
  258.     int c;
  259.     struct telnet *tn;
  260.  
  261.     tn = (struct telnet *)tn1;
  262.     sp = tn->session;
  263.  
  264.     /* Send whatever's typed on the terminal */
  265.     while((c = recvchar(sp->input)) != EOF){
  266.         usputc(sp->s,(char)c);
  267.         if(!tn->remote[TN_ECHO] && sp->record != NULLFILE)
  268.             putc(c,sp->record);
  269.  
  270.         /* By default, output is transparent in remote echo mode.
  271.          * If eolmode is set, turn a cr into cr-null.
  272.          * This can only happen when in remote echo (raw) mode, since
  273.          * the tty driver normally maps \r to \n in cooked mode.
  274.          */
  275.         if(c == '\r' && tn->eolmode)
  276.             usputc(sp->s,'\0');
  277.  
  278.         if(tn->remote[TN_ECHO])
  279.             usflush(sp->s);
  280.     }
  281.     /* Make sure our parent doesn't try to kill us after we exit */
  282.     sp->proc1 = NULLPROC;
  283. }
  284. int
  285. doecho(argc,argv,p)
  286. int argc;
  287. char *argv[];
  288. void *p;
  289. {
  290.     if(argc < 2){
  291.         if(Refuse_echo)
  292.             tprintf("Refuse\n");
  293.         else
  294.             tprintf("Accept\n");
  295.     } else {
  296.         if(argv[1][0] == 'r')
  297.             Refuse_echo = 1;
  298.         else if(argv[1][0] == 'a')
  299.             Refuse_echo = 0;
  300.         else
  301.             return -1;
  302.     }
  303.     return 0;
  304. }
  305. /* set for unix end of line for remote echo mode telnet */
  306. int
  307. doeol(argc,argv,p)
  308. int argc;
  309. char *argv[];
  310. void *p;
  311. {
  312.     if(argc < 2){
  313.         if(Tn_cr_mode)
  314.             tprintf("null\n");
  315.         else
  316.             tprintf("standard\n");
  317.     } else {
  318.         if(argv[1][0] == 'n')
  319.             Tn_cr_mode = 1;
  320.         else if(argv[1][0] == 's')
  321.             Tn_cr_mode = 0;
  322.         else {
  323.             tprintf("Usage: %s [standard|null]\n",argv[0]);
  324.             return -1;
  325.         }
  326.     }
  327.     return 0;
  328. }
  329.  
  330. /* The guts of the actual Telnet protocol: negotiating options */
  331. void
  332. willopt(tn,opt)
  333. struct telnet *tn;
  334. int opt;
  335. {
  336.     int ack;
  337.  
  338. #ifdef    DEBUG
  339.     printf("recv: will ");
  340.     if(uchar(opt) <= NOPTIONS)
  341.         printf("%s\n",T_options[opt]);
  342.     else
  343.         printf("%u\n",opt);
  344. #endif
  345.     
  346.     switch(uchar(opt)){
  347.     case TN_TRANSMIT_BINARY:
  348.     case TN_ECHO:
  349.     case TN_SUPPRESS_GA:
  350.         if(tn->remote[uchar(opt)] == 1)
  351.             return;        /* Already set, ignore to prevent loop */
  352.         if(uchar(opt) == TN_ECHO){
  353.             if(Refuse_echo){
  354.                 /* User doesn't want to accept */
  355.                 ack = DONT;
  356.                 break;
  357.             } else {
  358.                 /* Put tty into raw mode */
  359.                 tn->session->ttystate.edit = 0;
  360.                 tn->session->ttystate.echo = 0;
  361.                 sockmode(tn->session->s,SOCK_BINARY);
  362.                 sockmode(tn->session->input,SOCK_BINARY);
  363.                 sockmode(tn->session->output,SOCK_BINARY);
  364.                 if(tn->session->record != NULLFILE)
  365.                     filemode(tn->session->record,SOCK_BINARY);
  366.  
  367.             }
  368.         }
  369.         tn->remote[uchar(opt)] = 1;
  370.         ack = DO;            
  371.         break;
  372.     default:
  373.         ack = DONT;    /* We don't know what he's offering; refuse */
  374.     }
  375.     answer(tn,ack,opt);
  376. }
  377. void
  378. wontopt(tn,opt)
  379. struct telnet *tn;
  380. int opt;
  381. {
  382. #ifdef    DEBUG
  383.     printf("recv: wont ");
  384.     if(uchar(opt) <= NOPTIONS)
  385.         printf("%s\n",T_options[uchar(opt)]);
  386.     else
  387.         printf("%u\n",uchar(opt));
  388. #endif
  389.     if(uchar(opt) <= NOPTIONS){
  390.         if(tn->remote[uchar(opt)] == 0)
  391.             return;        /* Already clear, ignore to prevent loop */
  392.         tn->remote[uchar(opt)] = 0;
  393.         if(uchar(opt) == TN_ECHO){
  394.             /* Put tty into cooked mode */
  395.             tn->session->ttystate.edit = 1;
  396.             tn->session->ttystate.echo = 1;
  397.             sockmode(tn->session->s,SOCK_ASCII);
  398.             sockmode(tn->session->input,SOCK_ASCII);
  399.             sockmode(tn->session->output,SOCK_ASCII);
  400.             if(tn->session->record != NULLFILE)
  401.                 filemode(tn->session->record,SOCK_ASCII);
  402.         }
  403.     }
  404.     answer(tn,DONT,opt);    /* Must always accept */
  405. }
  406. void
  407. doopt(tn,opt)
  408. struct telnet *tn;
  409. int opt;
  410. {
  411.     int ack;
  412.  
  413. #ifdef    DEBUG
  414.     printf("recv: do ");
  415.     if(uchar(opt) <= NOPTIONS)
  416.         printf("%s\n",T_options[uchar(opt)]);
  417.     else
  418.         printf("%u\n",uchar(opt));
  419. #endif
  420.     switch(uchar(opt)){
  421.     case TN_SUPPRESS_GA:
  422.         if(tn->local[uchar(opt)] == 1)
  423.             return;        /* Already set, ignore to prevent loop */
  424.         tn->local[uchar(opt)] = 1;
  425.         ack = WILL;
  426.         break;
  427.     default:
  428.         ack = WONT;    /* Don't know what it is */
  429.     }
  430.     answer(tn,ack,opt);
  431. }
  432. void
  433. dontopt(tn,opt)
  434. struct telnet *tn;
  435. int opt;
  436. {
  437. #ifdef    DEBUG
  438.     printf("recv: dont ");
  439.     if(uchar(opt) <= NOPTIONS)
  440.         printf("%s\n",T_options[uchar(opt)]);
  441.     else
  442.         printf("%u\n",uchar(opt));
  443. #endif
  444.     if(uchar(opt) <= NOPTIONS){
  445.         if(tn->local[uchar(opt)] == 0){
  446.             /* Already clear, ignore to prevent loop */
  447.             return;
  448.         }
  449.         tn->local[uchar(opt)] = 0;
  450.     }
  451.     answer(tn,WONT,opt);
  452. }
  453. void
  454. answer(tn,r1,r2)
  455. struct telnet *tn;
  456. int r1,r2;
  457. {
  458.     char s[3];
  459.  
  460. #ifdef    DEBUG
  461.     switch(r1){
  462.     case WILL:
  463.         printf("sent: will ");
  464.         break;
  465.     case WONT:
  466.         printf("sent: wont ");
  467.         break;
  468.     case DO:
  469.         printf("sent: do ");
  470.         break;
  471.     case DONT:
  472.         printf("sent: dont ");
  473.         break;
  474.     }
  475.     if(r2 <= NOPTIONS)
  476.         printf("%s\n",T_options[r2]);
  477.     else
  478.         printf("%u\n",r2);
  479. #endif
  480.  
  481.     s[0] = IAC;
  482.     s[1] = r1;
  483.     s[2] = r2;
  484.     send(tn->session->s,s,3,0);
  485. }
  486. #ifdef    __TURBOC__
  487. /* Set end-of-line translation mode on file */
  488. static int
  489. filemode(fp,mode)
  490. FILE *fp;
  491. int mode;
  492. {
  493.     int omode;
  494.  
  495.     if(fp == NULLFILE)
  496.         return -1;
  497.  
  498.     if(fp->flags & _F_BIN)
  499.         omode = SOCK_BINARY;
  500.     else
  501.         omode = SOCK_ASCII;
  502.  
  503.     switch(mode){
  504.     case SOCK_BINARY:
  505.         fp->flags = _F_BIN;
  506.         setmode(fileno(fp),O_BINARY);
  507.         break;
  508.     case SOCK_ASCII:
  509.         fp->flags &= ~_F_BIN;
  510.         setmode(fileno(fp),O_TEXT);
  511.         break;
  512.     }
  513.     return omode;
  514. }
  515. #else
  516. static int
  517. filemode(fp,mode)
  518. FILE *fp;
  519. int mode;
  520. {
  521.     return 0;
  522. }
  523. #endif
  524.  
  525. /*
  526.     service_code - return port number for a service mnemonic
  527. */
  528.  
  529. int service_code(char *str)
  530. {
  531.     int     i;
  532.     char     sp[20];
  533.     char     *cp, *ip ;
  534.     struct svc *svc = services;
  535.  
  536.     cp = sp;
  537.     ip = str; 
  538.  
  539.     if    (!(i = strlen(str)) || i > 19 )
  540.         return -1;
  541.         
  542.     if (*str >= '0' && *str <= '9')            /* convert numeric str to integer */
  543.         return atoi(str);                            /* return port number                 */  
  544.  
  545.     while (*ip != '\0') {                        /* convert text to lower case         */
  546.         *cp++ = tolower(*ip);
  547.         ip++;
  548.     }
  549.  
  550.     *cp = '\0';
  551.     
  552.     while (svc->name) {                            /* scan the service code table    */
  553.           if (!strcmp(svc->name, sp)) 
  554.             return svc->service_code;
  555.           svc++;
  556.     }
  557.     
  558.     return -1;
  559. }
  560.  
  561.  
  562.  
  563.